from binascii import crc32
from ctypes import c_uint32
from threading import RLock
from time import time

countersLock = RLock()
yencbytes = 0
yenctime = 0

def get_counters():
	ret = None
	with countersLock:
		global yencbytes, yenctime
		ret = (yencbytes, yenctime)
	return ret
def reset_counters():
	with countersLock:
		global yencbytes, yenctime
		yencbytes = 0
		yenctime = 0
def inc_counters(bytes, timetaken):
	with countersLock:
		global yencbytes, yenctime
		yencbytes += bytes
		yenctime += timetaken

enc_table = ''.join([chr((i + 42) % 256) for i in xrange(256)])
def yencode(data):
	return str(data).translate(enc_table).replace('=', '=\x7d').replace('\x00', '=\x40').replace('\r', '=\x4d').replace('\n', '=\x4a')

#

def nntpyencwrap(encdata, name, fsize, psize, pcrc32, part, chars_per_line, lines_per_part): # part starts counting at 1
	t = []
	begin = (part - 1) * chars_per_line * lines_per_part + 1
	end = begin + psize - 1
	header = '=ybegin part=%d line=%d size=%d name=%s\r\n=ypart begin=%d end=%d\r\n' % (part, chars_per_line, fsize, name, begin, end)
	# print header
	t.append(header)
	# print '[%d bytes of binary]' % len(encdata)
	t.append(encdata) # assume encdata is from nntpyencpart and therefore ends with CRLF
	footer = '\r\n=yend size=%d part=%d pcrc32=%s' % (psize, part, pcrc32)
	# print footer
	t.append(footer)
	return ''.join(t)
#	
def nntpyencpart(data, chars_per_line):
	starttime = time()
	bytes = len(data)
	encdata = yencode(data)
	ucrc = c_uint32(0)
	ucrc.value = crc32(encdata)
	crcstr = '%08X' % ucrc.value
	lines = []
	pointer = 0
	while 1:
		try:
			if encdata[pointer] == '.':
				lines.append('=\x6e')
				lines.append(encdata[pointer + 1:pointer + chars_per_line - 1])
				pointer += chars_per_line - 1
			else:
				lines.append(encdata[pointer:pointer + chars_per_line])
				pointer += chars_per_line
			if lines[len(lines) - 1][-1] == '=':
				lines.append(encdata[pointer])
				pointer += 1
		except IndexError: # reached end of encdata
			lines.append(encdata[pointer:])
			pointer = 0
			lines.append('\r\n')
			break
		lines.append('\r\n')
	encdata = None # free some ram. who knows? this might prevent sending box into swap while joining
	partstr = ''.join(lines)
	lines = None # free some ram. who knows? this might prevent sending box into swap while constructing tuple
	inc_counters(bytes, time() - starttime)
	return (partstr, crcstr)

#